package org.dftproject.patml;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import modviewcontrol.Node;
import modviewcontrol.NodeIO;
import modviewcontrol.NodeUtils;

import org.dftproject.genesis.core.http.HttpManager;
import org.dftproject.genesis.core.persistence.IMemento;
import org.dftproject.patml.data.PatmlSite;
import org.dftproject.patml.factories.TngSiteFactory;
import org.w3c.dom.Document;

public class TngSite extends PatmlSite {
	
	private static Node patmlDocument;
	
	private final static Pattern queryStringPattern = Pattern.compile("^.*?\\?(.*?)(?:#.*)?$");
	private final static Pattern componentPattern = Pattern.compile("([^=&]+)=([^&]+)&");
	
	private final String tree;

	public TngSite(String url, String tree) {
		super(url);
		this.tree = tree;
	}

	@Override
	public Document getPersonData(String id) {
		String personUrl = getPersonUrl(id);
		if (personUrl == null)
			return null;

		String content = HttpManager.getDefault().getWebPage(personUrl);
		if (content == null)
			return null;
		
		String xml = getXml(personUrl, content);
		if (xml == null)
			return null;
		
		return Utils.domFromString(xml.replaceAll("&amp;|&", "&amp;"));
	}
	
	protected String getXml(String url, String content) {
		ArrayList<String> list = new ArrayList<String>();
		list.add(content);
		
		if (patmlDocument == null) {
			try {
				patmlDocument = NodeIO.load(new InputStreamReader(DataProvider.class.getResourceAsStream("tng.patml")));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace(System.err);
			}
		}
		
		return NodeUtils.getBasicXML(patmlDocument, list, Pattern.DOTALL, 0);
	}

	@Override
	public String getPersonId(String url) {
		Matcher matcher = queryStringPattern.matcher(url);
		if (matcher.matches()) {			
			String queryString = matcher.group(1);
			if (!queryString.endsWith("&"))
				queryString += "&";
			matcher = componentPattern.matcher(queryString);
			while (matcher.find()) {
				if ("personID".equalsIgnoreCase(matcher.group(1)))
					return matcher.group(2);
			}
		}
		
		return null;
	}

	@Override
	public String getPersonUrl(String id) {
		try {
			StringBuilder sb = new StringBuilder(getUrl());
			sb.append("getperson.php?personID=").append(URLEncoder.encode(id, "UTF-8"));
			if (tree != null)
				sb.append("&tree=").append(URLEncoder.encode(tree, "UTF-8"));
			return sb.toString();
		} catch (UnsupportedEncodingException e) {
			return null;
		}
	}

	public String getFactoryId() {
		return TngSiteFactory.ID;
	}

	public void saveState(IMemento memento) {
		memento.putString("url", getUrl());
		memento.putString("tree", tree);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = super.hashCode();
		result = prime * result + ((tree == null) ? 0 : tree.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (getClass() != obj.getClass())
			return false;
		final TngSite other = (TngSite) obj;
		if (tree == null) {
			if (other.tree != null)
				return false;
		} else if (!tree.equals(other.tree))
			return false;
		return true;
	}

	@Override
	public String getType() {
		return "The Next Generation of Genealogy Sitebuilding";
	}

}
